﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public static PlayerController _instance;

    public Transform camera_transform;// 镜头
    Vector3 m_CamRot; // 镜头的角度
    float m_CamRadius; // 镜头距离主角的半径
    float m_CamMaxRadius; // 最大的镜头距离
    float m_CamMinRadius; // 最小的镜头距离
    Vector3 Camera_Offset = new Vector3(0.05f, 0.1f, 0);//镜头的偏移量；
    float Zoom_Speed = 2.0f; // 镜头放大的速度
    float PI = 3.14159f;

    CharacterController M_ch;// 角色控制器
    Animator M_ani;// 动画

    public LayerMask m_ObjMask;// 可交互物品层？
    public LayerMask m_MonsterMask;// 怪兽层？

    public int Temp_Attack_Force; //临时的攻击力
    public int Attack_Force; // 攻击力
    public int Defense_Power; // 防御力

    public float Move_Speed;// 移动速度
    public float Rise_Speed;// 坠落速度
    public float M_Gravity;// 重力

    public float Health_Point;// 血量等级
    private int Max_Hunger = 10000;//饱食度上限
    private int Max_Thirsty = 10000;//口渴度上限
    public float Hunger_Degree;// 饱食度
    public float Thirst_Degree;// 口渴度
    bool is_rad;//是否处于辐射状态
    public float Radiation_Mag;//辐射强度
    public float Radiation_Point;// 辐射度
    public float Radiation_Rate = 1;//辐射抗性
    public float Radiation_down;//降低速度
    public float Radiation_Panic;// 在最高辐射的情况下能存活的时间

    public const float Max_Panic_Time = 120;
    public const int Normal_Attack_Force = 100;// 常规情况下的攻击力
    public const float Normal_Move_Speed = 8;// 标准速度
    public const int Max_HP = 11;//最大血条

    public float Panic_Damage_Speed = 1.0f;// 在最高辐射情况下的掉血速度
    public float Hungry_Damage_Speed = 0.01f;// 在饥饿情况下的掉血速度
    public float Thirsty_Damage_Speed = 0.01f;// 在口渴的情况下的掉血速度

    public int Hunger_speed;// 饱食度降低的速度
    public int Thirst_speed;// 口渴度降低的速度

    public static float JumpSpeed = 12f;
    //public bool isJump = true;// 跳跃状态
    public bool isDying = false;// 是否在辐射边缘
    public bool isNearDeath = false;// 是否已经临界且濒死

    private float Cooldown = 0.5f; // 攻击间隔
    public float lastTime = 0;// 上次攻击的时间

    public float Rotate_Speed = 480;// 转向速度
    public float Rotate_Angle = 0;// 转向角度
    public float Rotate_Threshold = 10;// 转向阈值

    private List<Buff> Buff_List = new List<Buff>();// 异常状态的列表

    private Transform M_transform;// 当前玩家的位置

    public Light FlashLight;
    public float Communicator_Mode = 0;
    public static float Change_Parameter = 3.0f;
    public const int mode_size = 1;

    public const int COMMUNICATOR_DIFFAULT = 0;
    public const int COMMUNICATOR_LIGHT = 1;

    private void Awake()
    {
        _instance = this;
    }

    // Start is called before the first frame update
    void Start()
    {
        FlashLight = transform.Find("flashlight").GetComponent<Light>();

        // 锁定鼠标
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
        Radiation_Point = 0;
        Health_Point = Max_HP;
        Hunger_Degree = 10000;
        Thirst_Degree = 10000;

        Radiation_Panic = Max_Panic_Time;

        Hunger_speed = 1;
        Thirst_speed = 2;
        Radiation_Rate = 1.0f;

        // 初始化各种数据
        Move_Speed = Normal_Move_Speed;
        //Rise_Speed = 0;
        M_Gravity = 1.0f;
        M_transform = this.transform;
        // 初始化攻击力和防御力
        Attack_Force = Normal_Attack_Force;//100表示全力输出
        Defense_Power = 1; // 默认值

        m_CamRadius = 2.0f;
        m_CamMaxRadius = 2.5f;
        m_CamMinRadius = 1.3f;
        M_ch = this.GetComponent<CharacterController>();
        M_ani = this.GetComponent<Animator>();
        //pack = this.GetComponent<Pack>();

        //debuff = new List<Buff>();
        //Current_Prop = null;
    }

    // Update is called once per frame
    void Update()
    {
        if (Health_Point == 0) return;

        if(Input.GetKeyDown(KeyCode.O))
        {
            Object_Manager._instance.Emerge_Obj(1001, this.transform.position);
        }

        Surviving();// 先进行即使的各个数据的扣除和变化
        Control();// 然后根据玩家的指令进行操作
    }

    // 玩家控制的影响
    private void Control()
    {
        // 获取鼠标移动的距离
        float rh = Input.GetAxis("Mouse X");
        float rv = Input.GetAxis("Mouse Y");

        // 旋转摄像头
        m_CamRot.x -= rv;
        m_CamRot.y += rh;
        if (m_CamRot.x > 60) m_CamRot.x = 60;
        if (m_CamRot.x < -60) m_CamRot.x = -60;
        camera_transform.eulerAngles = m_CamRot;

        // 角色移动
        float delta = Time.deltaTime;
        Vector3 motion = Vector3.zero;

        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            M_ani.SetBool("run", true);// 判定是否在跑步
        }
        if (Input.GetKeyUp(KeyCode.LeftShift)) M_ani.SetBool("run", false);// 判断是否在奔跑

        if (M_ani.GetBool("run"))
            MoveSpeed_Change(150);

        // 获得水平设置方向上面的分量
        float horizon = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");

        Vector2 front = new Vector2(1, 0);
        Vector2 face = new Vector2(vertical, -horizon);
        // 如果有方向的输入，则调整运动者的方向
        if (face.magnitude > 0.01f)
        {
            float Relative_angle = VectorAngle(front, face);
            float target_angle = Relative_angle + m_CamRot.y;
            float rotate_angle = toTarget(M_transform.eulerAngles.y, target_angle);

            float one_angle = Rotate_Speed * delta;
            if (one_angle < Mathf.Abs(rotate_angle))
            {
                Vector3 m_Rot = M_transform.eulerAngles;
                if (rotate_angle < 0) M_transform.eulerAngles = new Vector3(0, m_Rot.y - one_angle, 0);
                else M_transform.eulerAngles = new Vector3(0, m_Rot.y + one_angle, 0);
            }
            else
            {
                //M_transform.eulerAngles += new Vector3(0, rotate_angle, 0);
                M_transform.Rotate(new Vector3(0, rotate_angle, 0), Space.Self);
            }

            //M_transform.eulerAngles = new Vector3(0, target_angle, 0);

            motion.z = 1 * Move_Speed * delta;
            M_ani.SetTrigger("walk");
        }

        if (!M_ch.isGrounded) Rise_Speed -= M_Gravity;// 如果还在跳跃的过程，则水平速度降低
        else
        {
            Rise_Speed = 0;
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Rise_Speed = JumpSpeed;
                //this.GetComponent<Rigidbody>().AddForce(Vector3.up * 300);
                //isJump = true;
            }
        }
        motion.y += Rise_Speed * Time.deltaTime;

        // 滚轮的功能
        float wheel_move = Input.GetAxis("Mouse ScrollWheel");
        // 在按下Q的情况下使用滚轮是切换道具
        if (Input.GetKey(KeyCode.Q))
        {
            Communicator_Mode += (wheel_move * Change_Parameter);
            if (Communicator_Mode > mode_size + 1) Communicator_Mode -= mode_size + 1;
            if (Communicator_Mode < 0) Communicator_Mode += mode_size + 1;
            Debug.Log(Communicator_Mode);
        }
        else
        {
            m_CamRadius -= wheel_move * Zoom_Speed;
            m_CamRadius = Mathf.Clamp(m_CamRadius, m_CamMinRadius, m_CamMaxRadius);
        }

        if(Input.GetKeyUp(KeyCode.Q))
        {
            int result = (int)Communicator_Mode;
            Apply_Communicator_Change(result);
        }

        // 左键的功能
        if (Input.GetMouseButton(0))
        {
            bool isAttack = M_ani.GetBool("isBattle");
            if (isAttack) Debug.Log("isBattle");
            else Debug.Log("isB");
            if (isAttack)// 如果是在攻击状态就是用主武器
            {
                m_CamRadius = 0.7f;// 当在使用主武器攻击的时候将转型往前挪动
                if (Time.time - lastTime < Cooldown)// 如果还在冷却状态则无事发生
                {
                }
                else// 如果不在冷却
                {
                    // 主武器攻击的话得转换角色的朝向
                    M_transform.eulerAngles = new Vector3(0, m_CamRot.y, 0);
                    RaycastHit info;
                    bool Remote_hit;

                    Remote_hit = Physics.Raycast(camera_transform.position, camera_transform.TransformDirection(Vector3.forward), out info, m_MonsterMask);
                    if (Remote_hit)
                    {
                        if (info.transform.tag.CompareTo(Tags.enermy) == 0)
                        {
                            Debug.Log("击中目标：" + info.transform.name);
                        }
                    }

                    // 这里是攻击的代码
                    M_ani.SetTrigger("attack");
                    lastTime = Time.time;
                    Cooldown = Inventory._instance.Get_Main_Weapon_CoolDown();
                }
            }
            else
            {

            }
        }
        // 右键的功能
        if (Input.GetMouseButton(1))
        {
            bool isAttack = M_ani.GetBool("isBattle");
            if (isAttack)// 如果是在攻击状态就是用副武器
            {
                if (Time.time - lastTime < Cooldown)// 如果还在冷却状态则无事发生
                {
                }
                else// 如果不在冷却
                {
                    M_ani.SetTrigger("attack");
                    Debug.Log("攻击一次");
                    lastTime = Time.time;
                    Cooldown = Inventory._instance.Get_Sub_Weapon_CoolDown();
                    // 这里是攻击的代码
                }
            }
            else
            {

            }
        }

        // 用角色控制器提供的移动函数能够自动检测碰撞
        M_ch.Move(M_transform.TransformDirection(motion));
        Vector3 nCamera_Position = M_transform.position // 如果是子摄像机直接可以不需要加上这个物体坐标
            + m_CamRadius * new Vector3(-Mathf.Sin(2 * PI * m_CamRot.y / 360), Mathf.Sin(2 * PI * m_CamRot.x / 360), -Mathf.Cos(2 * PI * m_CamRot.y / 360));
        camera_transform.position = Vector3.Lerp(camera_transform.position, nCamera_Position, 0.2f);
        camera_transform.Translate(Camera_Offset, Space.Self);
        //camera_transform.Translate(new Vector3())

        // 下面这些操作都还没有做
        // 切换攻击的状态
        if (Input.GetKeyDown(KeyCode.F))
        {
            Transfer_State();
        }
        // 按Tab显示详细数据
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            PrintInfo();
        }
        // 按B显示背包内的东西
        if (Input.GetKeyDown(KeyCode.B))
        {
            Craft_List._instance.Refresh_Craft_Table();
            Inventory._instance.TransformState();
        }
        // 按R键在背包中快速使用回复类型的道具
        if (Input.GetKeyDown(KeyCode.R))
        {
            if(Health_Point < Max_HP)
            {
                Inventory._instance.Get_Fast_Cure();
            }
        }

        // 关于可互动物体的探知
        Debug.DrawRay(camera_transform.position, camera_transform.forward, Color.green);
        RaycastHit hit;
        if(Physics.Raycast(camera_transform.position, camera_transform.forward, out hit, 4.0f, m_ObjMask))
        {
            Debug.Log("射线击中：" + hit.collider.gameObject.name + "\n tag:" + hit.collider.tag);
            GameObject visable_obj = hit.collider.gameObject;
            Interactable interact_obj = (Interactable)visable_obj.GetComponent<Interactable>();
            if(interact_obj != null)
            {
                interact_obj.Get_Checked();
                if(Input.GetKeyDown(KeyCode.E))
                {
                    interact_obj.Activate();
                    //Destroy(visable_obj);
                }
            }
        }
    }

    // 时刻进行的结算
    private void Surviving()
    {
        // 不管怎么样先恢复原始的辐射接受度
        Radiation_Rate = 1.0f;
        // 当辐射度大于临界状态时
        if(Radiation_Point > 80)
        {
            isDying = true;
            if (Health_Point > 1) isNearDeath = false;
            Move_Speed = 2 * Normal_Move_Speed;
            Attack_Force = 200;
            // 掉血直到血量变成1
            if (!isNearDeath)
                Health_Point -= Panic_Damage_Speed;
            if (Health_Point <= 1)
            {
                Health_Point = 1;
                isNearDeath = true;
            }
            // 条子烧完了就直接游戏结束
            Radiation_Panic -= Time.deltaTime;
            if (Radiation_Panic <= 0) Die();
        }
        // 当辐射小于临界状态时
        else
        {
            isDying = false;
            isNearDeath = false;
            // 计算这一帧的行动速度
            // 用一个临时变量来计算出每一帧的战斗力然后赋给实际的面板数据
            Move_Speed = Normal_Move_Speed;
            Temp_Attack_Force = Normal_Attack_Force;
            // 根据辐射度判断失去饱食度或是饱水度的速度
            if (Radiation_Point > 40)// 高辐射状态
            {
                Hunger_speed = 2;
                Thirst_speed = 3;
                Temp_Attack_Force = Temp_Attack_Force * 6 / 5;
            }// 没有辐射的状态
            else// 普通的辐射值
            {
                Hunger_speed = 1;
                Thirst_speed = 2;
            }
            // 失去一定的饱腹和饱水值
            Hunger_Change(-Hunger_speed * Time.deltaTime);
            Thirst_Change(-Thirst_speed * Time.deltaTime);

            // 饥饿度判定
            if (Hunger_Degree <= 0)
            {
                Hunger_Degree = 0;
                HP_Change(-Hungry_Damage_Speed * Time.deltaTime);
            }
            // 根据饱食度更变当前的速度和攻击力 我用的公式是 力量 = 力量 * （饱食度 + 10000）/ 20000；
            Temp_Attack_Force = (int)(Temp_Attack_Force * (Hunger_Degree + 10000) / 20000);
            Move_Speed = Move_Speed * (Hunger_Degree + 10000) / 20000;

            // 口渴度判定
            if (Thirst_Degree <= 0)
            {
                Thirst_Degree = 0;
                HP_Change(-Thirsty_Damage_Speed * Time.deltaTime);
            }
            // 根据饱水度变更当前的速度和攻击力
            Temp_Attack_Force = (int)(Temp_Attack_Force * (Thirst_Degree + 10000) / 20000);
            Move_Speed = Move_Speed * (Thirst_Degree + 10000) / 20000;

            // 背包判定
            int Load_Percent = Inventory._instance.GetDebuff();
            Move_Speed = Move_Speed * Load_Percent / 100;
            Temp_Attack_Force = Temp_Attack_Force * Load_Percent / 100;

            // Debuff的判定
            Buff_Process();

            Attack_Force = Temp_Attack_Force; // 获得当前的攻击力
        }
        if (is_rad)
        {
            Get_Radiation(Radiation_Mag * Time.deltaTime);
        }
        else
        {
            Get_Radiation(-Radiation_down * Time.deltaTime);
        }
    }

    // 受到血量伤害
    public void HP_Change(float change_hp)
    {
        Health_Point += change_hp;
        if (Health_Point > Max_HP) Health_Point = Max_HP;
        if (Health_Point <= 0) Die();
        // 根据剩余的血量修改UI
        switch (Health_Point)
        {
            default: break;
        }
    }
    // 受到攻击(看描述说不定还有护甲这样的东西)
    public void OnAttack(float Hurt_Point)
    {

    }

    // 受到辐射(要考虑到药物和装备区的效果)
    public void Get_Radiation(float radiation)
    {
        int Equip_Anti_Radiation = Inventory._instance.Get_Radiation_Percentage();

        Radiation_Point += radiation * Radiation_Rate * (100 - Equip_Anti_Radiation) / 100;
    }
    // 辐射度更变
    public void Get_Direct_Radiation(float radiation)
    {
        Radiation_Point += radiation;
    }
    // 饥饿度变更
    public void Hunger_Change(float value)
    {
        Hunger_Degree += value;
        if (Hunger_Degree > Max_Hunger) Hunger_Degree = Max_Hunger;
    }
    // 饱水度变更
    public void Thirst_Change(float value)
    {
        Thirst_Degree += value;
        if (Thirst_Degree > Max_Thirsty) Thirst_Degree = Max_Thirsty;
    }
    // 力量变更
    public void Attack_Change(int percentage)
    {
        Temp_Attack_Force = Temp_Attack_Force * percentage / 100;
    }
    // 速度变更
    public void MoveSpeed_Change(int percentage)
    {
        Move_Speed = Move_Speed * percentage / 100;
    }
    // 辐射接受能力变更
    public void Change_Radiation_Rate(float percentage)
    {
        Radiation_Rate *= percentage;
    }
    // 更换通讯器的功能
    public void Apply_Communicator_Change(int mode)
    {
        Communicator_Mode = mode + 0.5f;
        switch(mode)
        {
            case COMMUNICATOR_DIFFAULT:
                FlashLight.enabled = false;
                break;
            case COMMUNICATOR_LIGHT:
                FlashLight.enabled = true;
                break;
        }
    }

    // 切换战斗状态
    public void Transfer_State()
    {
        bool isBattle = M_ani.GetBool("isBattle");
        if (isBattle == true)
        {
            M_ani.SetBool("isBattle", false);
        }
        else
        {
            M_ani.SetBool("isBattle", true);
        }
    }

    // 先不管死了啥操作，随便写一个接口
    public void Die()
    {
        Debug.Log("角色已死亡");
        M_ani.SetBool("death", true);
    }
    // 返回二维向量的夹角
    public float VectorAngle(Vector2 from, Vector2 to)
    {
        float angle;

        Vector3 cross = Vector3.Cross(from, to);
        angle = Vector2.Angle(from, to);
        return cross.z > 0 ? -angle : angle;
    }

    public float toTarget(float from, float to)
    {
        float diff = to - from;// 两个输入参数之间的差值
        while (diff > 360) diff -= 360;
        while (diff < 0) diff += 360;

        if (diff > 180) return diff - 360;
        else return diff;
    }
    // 显示详细数据
    public void PrintInfo()
    {
        Debug.Log("饱食度：" + Hunger_Degree.ToString());
        Debug.Log("饱水度：" + Thirst_Degree.ToString());
        Debug.Log("力量：" + Attack_Force.ToString() + "%");
        Debug.Log("辐射度：" + Radiation_Point.ToString());
        Debug.Log("移动速度：" + Move_Speed.ToString());
        Debug.Log("饥饿速度：" + Hunger_speed.ToString());
        Debug.Log("口渴速度：" + Thirst_speed.ToString());
        Debug.Log("临界剩余时间：" + Radiation_Panic.ToString());
    }
    // 处理所有的buff
    public void Buff_Process()
    {
        //Debug.Log("Buff_process");
        // 结算所有的负面buff
        foreach(Buff buff in Buff_List)
        {
            buff.activate(Time.deltaTime);
        }
        int i = 0;// 删除掉已经过时的buff
        int listSize = Buff_List.Count;
        while (i < listSize)
        {
            if(Buff_List[i].isEnd())
            {
                Buff_List.RemoveAt(i);
                listSize = Buff_List.Count;
                continue;
            }
            i++;       
        }

    }
    // 通过id获得一个buff
    public void Get_Buff(int id, float Last_Time = -1)
    {
        Buff coordBuff = BuffInfo._instance.getBuffInfobyid(id);
        if (Last_Time > 0)
            coordBuff.lasttime = Last_Time;

        bool is_Exist = false;
        foreach(Buff the_buff in Buff_List)
        {
            if(the_buff.id == coordBuff.id)
            {
                the_buff.lasttime += coordBuff.lasttime;
                is_Exist = true;
                break;
            }
        }
        if (!is_Exist)
        {
            Buff_List.Add(coordBuff);
        }
        else return;
    }

    public void Eliminate_Buff(int id)
    {
        int i = 0;
        int ListSize = Buff_List.Count;
        while(i < ListSize)
        {
            if(Buff_List[i].id == id)
            {
                Buff_List.RemoveAt(i);
                ListSize = Buff_List.Count;
                continue;
            }
        }
        i++;
    }

    /*private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.tag == "Plane")
        {
            Debug.Log("isFalling-collision");
            isJump = false;
            Rise_Speed = 0;
        }
    }*/
}
